﻿@inject IModelCatalogService _modelCatalogService
@inject ChatState _chatState
@inject ISnackbar Snackbar

@implements IDisposable

<MudAutocomplete Value="CurrentValue"
                 T="string" 
                 Immediate="true" 
                 CoerceValue="@coerceValue"
                 CoerceText="@coerceText"
                 SearchFunc="@SearchAsync"
                 Clearable="true"
                 ResetValueOnEmptyText="true"
                 ShowProgressIndicator="true" 
                 ProgressIndicatorColor="Color.Primary"
                 CloseIcon="@Icons.Material.Filled.Search" 
                 AdornmentColor="Color.Primary" 
                 MaxItems="null"
                 Margin="Margin.Dense"
                 Style="width: 400px"
                 ValueChanged="OnValueChanged"/>

@code
{
    public ModelCatalogResponse ModelCatalog { get; set; } = new();
    private string CurrentValue { get; set; } = string.Empty;
    private string ServiceId { get; set; } = string.Empty;

    private bool coerceText;
    private bool coerceValue;

    protected override async Task OnInitializedAsync()
    {
        _chatState.SelectedModelChanged += StateHasChanged;
        _chatState.ServiceIdChanged += StateHasChanged;
        _chatState.SelectedAssistantChanged += SetDefaultModel;
        _chatState.LastFetchedModelsCatalogChanged += StateHasChanged;
        _chatState.ModelsCatalogRefreshed += async () => await LoadModelCatalog();

        await LoadModelCatalog();
        SetDefaultModel();
    }

    private async Task LoadModelCatalog()
    {
        var response = await _modelCatalogService.BrowseModelsCatalog();
        var modelCatalog = response.Value;

        if(!response.Succeeded)
        {
            ShowSnackbar("Failed to load model catalog. Please try again.", Severity.Error);
        }

        if(modelCatalog is not null)
        {
            ModelCatalog = modelCatalog;
            _chatState.SetLastFetchedModelsCatalog(modelCatalog.LastFetched);
        }
    }

    private void SetDefaultModel()
    {
        var selectedModel = _chatState.SelectedAssistant?.DefaultModel;

        if (IsValidModel(selectedModel!))
        {
            CurrentValue = selectedModel!;
            _chatState.SetSelectedModel(selectedModel!);

            var serviceId = ModelCatalog.Models.SingleOrDefault(x => x.Name == CurrentValue)?.Provider ?? string.Empty;
            _chatState.SetServiceId(serviceId);
        }
    }

    private async Task<IEnumerable<string>?> SearchAsync(string value)
    {
        if (string.IsNullOrEmpty(value))
        {
            return ModelCatalog.Models.Select(model => model.Name);
        }

        var result = ModelCatalog.Models
            .Where(x => x.Name.Contains(value, StringComparison.InvariantCultureIgnoreCase))
            .Select(model => model.Name);

        return await Task.FromResult(result);
    }

    private void OnValueChanged(string value)
    {
        CurrentValue = value.IsEmpty() ? string.Empty : value;
        var serviceId = ModelCatalog.Models.SingleOrDefault(x => x.Name == value)?.Provider ?? string.Empty;
        
        _chatState.SetServiceId(serviceId);
        _chatState.SetSelectedModel(CurrentValue);
    }

    private void OnSelectedModelChanged() 
        => _chatState.SetSelectedModel(CurrentValue);

    private void OnSelectedAssistantChanged() 
        => SetDefaultModel();

    private bool IsValidModel(string value) 
        => value.IsNotEmpty() && ModelCatalog.Models.Any(model => model.Name == value);

    private void ShowSnackbar(string message, Severity severity)
    {
        Snackbar.Configuration.PositionClass = Defaults.Classes.Position.TopRight;

        Snackbar.Add(message, severity, options =>
        {
            options.HideTransitionDuration = 100;
        });
    }

    public void Dispose()
    {
        _chatState.SelectedModelChanged -= StateHasChanged;
        _chatState.ServiceIdChanged -= StateHasChanged;
        _chatState.SelectedAssistantChanged -= SetDefaultModel;
        _chatState.LastFetchedModelsCatalogChanged -= StateHasChanged;
        _chatState.ModelsCatalogRefreshed -= async () => await LoadModelCatalog();
    }
}
